# from selenium.webdriver.common.action_chains import ActionChains
# from selenium import webdriver
# import time
#
#
# options = webdriver.ChromeOptions()
# options.add_argument(r"--user-data-dir=C:\Users\Administrator\AppData\Local\Google\Chrome\User Data")
# driver = webdriver.Chrome(options=options)
# driver.get("https://www.jianshu.com/")
# driver.maximize_window()
# time.sleep(5)
#
# driver.find_element("xpath","//div[@class='width-limit']/a[@id='sign_in']").click()
# time.sleep(5)
# driver.find_element("xpath","//input[@id='session_email_or_mobile_number']").send_keys("123345")
# driver.find_element("xpath","//input[@id='session_password']").send_keys("helloworld")
# driver.find_element("xpath","//button[@id='sign-in-form-submit-btn']").click()
# time.sleep(2)
# slider_button = driver.find_element("xpath","//div[@class='geetest_slider_button']")
#
# ActionChains(driver).click_and_hold(slider_button).perform()
# for i in range(10):
#     ActionChains(driver).move_by_offset(10,0).perform()
#     time.sleep(1)
# ActionChains(driver).release().perform()



import time
from selenium import webdriver
from selenium.webdriver import ActionChains
from PIL import Image
import random


class Crack():

    # 触发验证码
    def __init__(self):
        options = webdriver.ChromeOptions()
        # 此步骤很重要，设置为开发者模式，防止被各大网站识别出来使用了Selenium
        options.add_experimental_option('excludeSwitches', ['enable-automation'])
        # 就是这一行告诉chrome去掉了webdriver痕迹，令navigator.webdriver=false，极其关键
        options.add_argument("--disable-blink-features=AutomationControlled")
        # 还有其他options配置，此处和问题无关，略去
        self.driver = webdriver.Chrome(options=options)
        self.driver.maximize_window()
        self.driver.get('https://passport.haodf.com/nusercenter/showlogin?forward=https%3A%2F%2Fwww.haodf.com%2Fbingcheng%2F8898690111.html')
        time.sleep(4)
        self.driver.find_element("xpath","//div[@class='tab']").click()
        time.sleep(2)
        self.driver.find_element("xpath","//input[@placeholder='用户名/手机号/邮箱']").send_keys("13246579879")
        self.driver.find_element("xpath","//input[@placeholder='请输入密码']").send_keys("12345")
        time.sleep(1)
        self.driver.find_element("xpath","//div[@class='status_icon unselected']").click()
        time.sleep(1)
        self.driver.find_element("xpath","//button[@class='submit']").click()
        time.sleep(5)

    # 获取验证码的图片（包括带阴影的背景图和不带阴影的背景图）
    def get_images(self):
        # 隐藏滑块
        myjs = 'document.getElementsByClassName("geetest_canvas_slice")[0].style.display="none";'
        self.driver.execute_script(myjs)
        # 页面截屏，验证码背景图带阴影
        self.driver.save_screenshot("./带阴影+背景图的验证码整个网页.png")
        # 查找定位带阴影验证码背景图的元素
        elem = self.driver.find_element("xpath",'//canvas[@class="geetest_canvas_bg geetest_absolute"]')
        # 获取elem的位置和尺寸
        location = elem.location
        size = elem.size
        left = location['x']
        top = location['y']
        right = left + size['width']
        bottom = top + size['height']
        print('验证码位置：', left, top, right, bottom)
        # 裁剪，截取带阴影的背景
        screenshot = Image.open("./带阴影+背景图的验证码整个网页.png")
        captcha = screenshot.crop((left, top, right, bottom))
        bg_filename = './阴影+背景验证码图片.png'
        captcha.save(bg_filename)
        # 恢复小图块的显示
        myjs = 'document.getElementsByClassName("geetest_canvas_slice")[0].style.display="block";'
        self.driver.execute_script(myjs)
        # 不带阴影的背景图
        # 默认 不带阴影背景是隐藏的，显示出来
        myjs = 'document.getElementsByClassName("geetest_canvas_fullbg")[0].style.display="block";'
        self.driver.execute_script(myjs)
        # 页面截屏，验证码背景图不带阴影
        self.driver.save_screenshot("不带阴影的背景图片整个网页.png")
        # 查找不带阴影的背景图
        elem = self.driver.find_element("xpath",'//canvas[@class="geetest_canvas_fullbg geetest_fade geetest_absolute"]')
        # 获取elem的位置和尺寸
        location = elem.location
        size = elem.size
        left = location['x']
        top = location['y']
        right = left + size['width']
        bottom = top + size['height']
        # 裁剪，获取不带阴影的背景图
        screenshot = Image.open("不带阴影的背景图片整个网页.png")
        captcha = screenshot.crop((left, top, right, bottom))
        fullbg_filename = './不带阴影的背景图片验证码.png'
        # 保存不带阴影的背景图
        captcha.save(fullbg_filename)
        # 恢复隐藏不带阴影背景
        myjs = 'document.getElementsByClassName("geetest_canvas_fullbg")[0].style.display="none";'
        self.driver.execute_script(myjs)

    # 计算滑块移动的距离
    def get_gap(self):
        # 加载验证码的背景图
        bg_filename = './阴影+背景验证码图片.png'
        fullbg_filename = './不带阴影的背景图片验证码.png'
        bg_img = Image.open(bg_filename)
        fullbg_img = Image.open(fullbg_filename)
        # Image对象size属性：表示图片尺寸（宽，高）
        for x in range(0, bg_img.size[0]):  # 水平方向
            for y in range(bg_img.size[1]):  # 垂直方向
                pix1 = bg_img.load()[x, y] # 按坐标获取图片的RGB值
                pix2 = fullbg_img.load()[x, y]
                # 判断像素是否差别过大
                threshold = 60
                # pix1[0] == red  pix1[1] == green   pix1[2] == blue(0~255)
                if abs(pix1[0] - pix2[0]) < threshold and abs(pix1[1] - pix2[1]) < threshold and abs(
                                pix1[2] - pix2[2]) < threshold:
                    pass
                else:
                    return x

    # 根据偏移量获取移动的轨迹
    def get_track(self, distance):
        distance += 20  # 先滑过一点，最后再反着滑动回来
        # 移动轨迹
        track = []
        # 当前位移
        current = 0
        # 减速阈值
        mid = distance * 0.7
        # 时间间隔
        t = 0.1
        # 初速度
        v = 0
        while current < distance:
            if current < mid:
                a = random.randint(10,40)
            else:
                a = random.randint(-24,-10)
            # 初速度
            v0 = v
            # 当前速度
            v = v0 + a * t
            # 移动的位移 v0t + 1/2 at^2
            move = v0 * t + 1 / 2 * a * t * t
            # 当前的位移
            current += move
            # 加入轨迹
            track.append(round(move))

        move = distance - current
        track.append(round(move))
        return track

    # 根据轨迹，模拟拖动滑块
    def move_to_gap(self, track):
        # 找滑块按住
        slider = self.driver.find_element("xpath",'//div[@class="geetest_slider_button"]')
        ActionChains(self.driver).click_and_hold(slider).perform()

        # 滑动 模拟人的停顿
        while track:
            if len(track) == 1:
                x = track.pop() + random.randint(-3,3)
            else:
                x = track.pop()
            if random.random() < 0.1:
                ActionChains(self.driver).move_by_offset(xoffset=x, yoffset=1).perform()
                time.sleep(random.random())
            else:
                ActionChains(self.driver).move_by_offset(xoffset=x, yoffset=1).perform()

        # 鼠标抬起 释放滑块
        ActionChains(self.driver).release(slider).perform()


if __name__ == "__main__":

    crack = Crack()
    # 获取一张没有滑块和阴影的纯背景图 和 一张只有阴影的图
    crack.get_images()
    # 计算阴影像素 距离左边界的像素距离
    distance = crack.get_gap()
    # 生成移动的轨迹
    track = crack.get_track(distance - 25)
    print(track)
    # 模拟拖动滑块到阴影缺口位置
    crack.move_to_gap(track)

